package com.market.domain;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;

import javax.faces.context.FacesContext;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import com.market.domain.Order.STATUS;
import com.market.domain.transients.Email;

@Entity
@Table(name = "user")
public class User extends BaseObject implements UserDetails {

	/**
	 * 
	 */
	private static final long serialVersionUID = -3586135704022996105L;

	@Transient
	public Boolean getIsHaveMessage() {
		if (this.messages.size() > 0) {
			return Boolean.TRUE;
		}
		return Boolean.FALSE;
	}

	public enum LANGUAGE {
		ENGLISH(Locale.ENGLISH), FRENCH(Locale.CANADA_FRENCH), CHINESE(
				Locale.CHINESE);
		Locale locale;

		private LANGUAGE(Locale locale) {
			this.locale = locale;
		}

		public Locale getLocale() {
			return this.locale;
		}

		public String getLabel() {
			java.util.ResourceBundle resBundle = ResourceBundle.getBundle(
					"com.market.messages", this.locale);
			return resBundle.getString("language");
		}
	}

	public enum TITLE {
		MISTER, MISSES, MISS;
		private String title;

		private String getMessage(String key) {
			Locale locale = FacesContext.getCurrentInstance().getViewRoot()
					.getLocale();
			java.util.ResourceBundle resBundle = ResourceBundle.getBundle(
					"com.market.messages", locale);
			return resBundle.getString(key);
		}

		public String getLabel() {
			return this.getMessage("USER_TITLE_" + this.toString());
		}
	}

	public String[] getPasswordQuestionList() {
		String questionList = super.getMessage("passwordQuestionList");
		return questionList.split(",");
	}

	@Override
	public boolean equalsId(Object o) {
		if ((o instanceof User) && ((User) o).getId().equals(this.id)) {
			return true;
		}

		return false;
	}

	/**
	 * This method is implement UserDetails,and UserDetails is used by
	 * UserManagerImpl's loadUserByUsername method
	 */
	@Transient
	public Collection<GrantedAuthority> getAuthorities() {
		Set<GrantedAuthority> authorities = new LinkedHashSet<GrantedAuthority>();
		authorities.addAll(roles);
		return authorities;
	}

	@Transient
	public String generateActivatedCode() {
		java.util.Random r = new java.util.Random();
		String password = "";
		String[] characters = "a,1,b,2,c,3,d,4,e,5,f,6,g,7,h,8,i,9,j,0,k,1,r,2,m,3,n,4,o,5,p,6,q,7,r,8,s,9,t,0,u,1,v,2,w,3,x,5,y,4,z,5"
				.split(",");
		int index;
		for (int i = 0; i < 40; i++) {
			index = r.nextInt(52);
			password = password + characters[index];
		}
		return password;
	}

	@Transient
	public Email getWelcomeEmail() {
		Email welcomeEmail = new Email();
		welcomeEmail.setTo(this.getEmail());
		welcomeEmail.setFrom(this.getMessage("ourEmail"));
		welcomeEmail.setSubject(super.getMessage("welcomeTo") + " "
				+ super.getMessage("webSiteName"));
		welcomeEmail.setWebSiteName(super.getMessage("webSiteName"));
		String text = super.getMessage("dearCustomer") + ","
				+ super.getMessage("pleaseKeepThisEmail") + ","
				+ super.getMessage("yourPasswordIs") + ":<br/>"
				+ this.getPassword() + "<br/><br/>"
				+ super.getMessage("yourAccountIsInActivate")
				+ ":<br/><br/>http://" + super.getMessage("webSiteName")
				+ "/public/activateAccount.xhtml?id=" + this.id
				+ "&activateCode=" + this.getActivateCode() + "<br/><br/>"
				+ super.getMessage("thankYouForRegistering");
		welcomeEmail.setContent(text);
		return welcomeEmail;
	}

	@Transient
	public Email getPasswordRemindEmail() {
		Locale userLocale = this.language.getLocale();
		Email passwordEmail = new Email();
		passwordEmail.setTo(this.getEmail());
		passwordEmail.setWebSiteName(super
				.getMessage("webSiteName", userLocale));
		passwordEmail.setFrom(this.getMessage("ourEmail", userLocale));
		passwordEmail.setSubject(super.getMessage("webSiteName", userLocale)
				+ " " + super.getMessage("passwordRemind", userLocale));
		String text = super.getMessage("dearCustomer", userLocale) + " "
				+ this.lastName + " " + this.firstName + "<br/><br/><br/>"
				+ super.getMessage("yourPasswordIs", userLocale) + ":"
				+ this.password + ". <br/><br/>"
				+ super.getMessage("thankYouForContact", userLocale) + ".";
		passwordEmail.setContent(text);
		return passwordEmail;
	}

	@Transient
	public boolean getIsCreditPayable() {
		return this.balance > 2D;
	}

	@Transient
	public Boolean getIsHaveUndeliveredOrder() {
		for (Order order : this.orders) {
			if (order.getStatus() == STATUS.RECEIVED
					|| order.getStatus() == STATUS.CONFIRMED
					|| order.getStatus() == STATUS.PREPARED) {
				return Boolean.TRUE;
			}
		}
		return Boolean.FALSE;
	}

	@Transient
	private boolean isLogin = false;

	public boolean getIsLogin() {
		return isLogin;
	}
	
	public void setIsLogin(boolean isLogin) {
		this.isLogin = isLogin;
	}

	public String getBalanceLabel() {
		return super.formatDoubleToString(this.getBalance());		
	}

	public Boolean getIsTelehponeEmpty() {
		if (this.telephone == null || this.telephone.isEmpty()) {
			return Boolean.TRUE;
		}
		return Boolean.FALSE;
	}
	
	public String getConfirmPassword() {
		return confirmPassword;
	}

	public void setConfirmPassword(String confirmPassword) {
		this.confirmPassword = confirmPassword;
	}

	public String getNewPassword() {
		return newPassword;
	}

	public void setNewPassword(String newPassword) {
		this.newPassword = newPassword;
	}

	public String getConfirmNewPassword() {
		return confirmNewPassword;
	}

	public void setConfirmNewPassword(String confirmNewPassword) {
		this.confirmNewPassword = confirmNewPassword;
	}

	/**
	 * This property is also use for input password from view temporarily when
	 * login by telephone. Because user can choose to login by email or
	 * telephone, so need two property for input password.
	 */
	@Transient
	private String confirmPassword;
	
	@Transient
	private String newPassword;
	@Transient
	private String confirmNewPassword;
	

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id = 0L;
	@Column(length = 50)
	private String firstName;
	@Column(length = 50)
	private String lastName;
	@Column(length = 50)
	private String password;
	@Column(length = 350)
	private String passwordQuestion;
	@Column(length = 100)
	private String passwordAnswer;
	@Column(length = 150)
	private String address;
	@Column(length = 50, nullable = false, unique = true)
	private String telephone;
	@Column(length = 50)
	private String mobilePhone;
	@Column(length = 100, nullable = false, unique = true)
	private String email;
	@Column(columnDefinition = "Double DEFAULT 0")
	private Double balance = 0D;
	@Column(length = 50)
	private String accessCode;
	@Column(length = 50)
	private String activateCode;
	@Column(columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
	@Temporal(TemporalType.TIMESTAMP)
	private Date createdDate;
	@ManyToMany(fetch = FetchType.LAZY)
	private List<Role> roles = new ArrayList<Role>();
	@ManyToOne(fetch = FetchType.EAGER)
	Location dropOffLocation;
	@ManyToMany(mappedBy = "users", fetch = FetchType.LAZY)
	private List<Message> messages = new ArrayList<Message>();
	@OneToMany(mappedBy = "customer", fetch = FetchType.LAZY)
	private List<Order> orders = new ArrayList<Order>();
	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	private List<AccountRecord> accountRecords = new ArrayList<AccountRecord>();
	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	private List<UserActivityRecord> userActivityRecords = new ArrayList<UserActivityRecord>();
	@Column(columnDefinition = "bit(1) default 1")
	private Boolean isEmailOrderStatus = Boolean.TRUE;
	@Column(columnDefinition = "bit(1) default 0")
	private Boolean isEmailStatusConfirm = Boolean.TRUE;
	@Column(columnDefinition = "bit(1) default 0")
	private Boolean isEmailStatusPrepare = Boolean.TRUE;
	@Column(columnDefinition = "bit(1) default 0")
	private Boolean isEmailStatusDeliver = Boolean.TRUE;
	@Column(columnDefinition = "bit(1) default 0")
	private Boolean isEmailStatusPay = Boolean.TRUE;
	@Column(columnDefinition = "bit(1) default 0")
	private Boolean isEmailStatusCancel = Boolean.TRUE;
	@Column(columnDefinition = "bit(1) default 0")
	private Boolean isPrepaid = Boolean.FALSE;
	@Column(nullable = false, columnDefinition = "bit(1) DEFAULT 0")
	private Boolean isActivated = Boolean.FALSE;
	@Column(nullable = false, columnDefinition = "bit(1) DEFAULT 1")
	private Boolean isEnabled = Boolean.TRUE;
	@Column(nullable = false, columnDefinition = "bit(1) DEFAULT 0")
	private Boolean isExpired = Boolean.FALSE;
	@Column(nullable = false, columnDefinition = "bit(1) DEFAULT 0")
	private Boolean isLocked = Boolean.FALSE;
	@Enumerated(EnumType.STRING)
	@Column(length = 30)
	private LANGUAGE language = LANGUAGE.ENGLISH;
	@Enumerated(EnumType.STRING)
	private TITLE title;
	@Column(length = 1500)
	private String memo;

	@Override
	public String toString() {
		return "User [isLogin=" + isLogin + ", id=" + id + ", firstName="
				+ firstName + ", lastName=" + lastName + ", address=" + address
				+ ", telephone=" + telephone + ", mobilePhone=" + mobilePhone
				+ ", email=" + email + ", balance=" + balance + ", accessCode="
				+ accessCode + ", activateCode=" + activateCode
				+ ", createdDate=" + createdDate + ",isPrepaid=" + isPrepaid
				+ ", isActivated=" + isActivated + ", isDisabled=" + isEnabled
				+ ", language=" + language + ", title=" + title + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((accessCode == null) ? 0 : accessCode.hashCode());
		result = prime * result
				+ ((activateCode == null) ? 0 : activateCode.hashCode());
		result = prime * result + ((address == null) ? 0 : address.hashCode());
		result = prime * result + ((balance == null) ? 0 : balance.hashCode());
		result = prime * result
				+ ((createdDate == null) ? 0 : createdDate.hashCode());
		result = prime * result
				+ ((dropOffLocation == null) ? 0 : dropOffLocation.hashCode());
		result = prime * result + ((email == null) ? 0 : email.hashCode());
		result = prime * result
				+ ((firstName == null) ? 0 : firstName.hashCode());
		result = prime * result
				+ ((isActivated == null) ? 0 : isActivated.hashCode());
		result = prime * result
				+ ((isEnabled == null) ? 0 : isEnabled.hashCode());
		result = prime * result + (isLogin ? 1231 : 1237);
		result = prime * result + (isPrepaid ? 1231 : 1237);
		result = prime * result
				+ ((language == null) ? 0 : language.hashCode());
		result = prime * result
				+ ((lastName == null) ? 0 : lastName.hashCode());
		result = prime * result
				+ ((mobilePhone == null) ? 0 : mobilePhone.hashCode());
		result = prime * result
				+ ((telephone == null) ? 0 : telephone.hashCode());
		result = prime * result + ((title == null) ? 0 : title.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		User other = (User) obj;
		if (accessCode == null) {
			if (other.accessCode != null)
				return false;
		} else if (!accessCode.equals(other.accessCode))
			return false;
		if (activateCode == null) {
			if (other.activateCode != null)
				return false;
		} else if (!activateCode.equals(other.activateCode))
			return false;
		if (address == null) {
			if (other.address != null)
				return false;
		} else if (!address.equals(other.address))
			return false;
		if (balance == null) {
			if (other.balance != null)
				return false;
		} else if (!balance.equals(other.balance))
			return false;
		if (createdDate == null) {
			if (other.createdDate != null)
				return false;
		} else if (!createdDate.equals(other.createdDate))
			return false;
		if (dropOffLocation == null) {
			if (other.dropOffLocation != null)
				return false;
		} else if (!dropOffLocation.equals(other.dropOffLocation))
			return false;
		if (email == null) {
			if (other.email != null)
				return false;
		} else if (!email.equals(other.email))
			return false;
		if (firstName == null) {
			if (other.firstName != null)
				return false;
		} else if (!firstName.equals(other.firstName))
			return false;
		if (isActivated == null) {
			if (other.isActivated != null)
				return false;
		} else if (!isActivated.equals(other.isActivated))
			return false;
		if (isEnabled == null) {
			if (other.isEnabled != null)
				return false;
		} else if (!isEnabled.equals(other.isEnabled))
			return false;
		if (isLogin != other.isLogin)
			return false;
		if (isPrepaid != other.isPrepaid)
			return false;
		if (language != other.language)
			return false;
		if (lastName == null) {
			if (other.lastName != null)
				return false;
		} else if (!lastName.equals(other.lastName))
			return false;
		if (mobilePhone == null) {
			if (other.mobilePhone != null)
				return false;
		} else if (!mobilePhone.equals(other.mobilePhone))
			return false;
		if (telephone == null) {
			if (other.telephone != null)
				return false;
		} else if (!telephone.equals(other.telephone))
			return false;
		if (title != other.title)
			return false;
		return true;
	}

	

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	

	public String getPasswordQuestion() {
		return passwordQuestion;
	}

	public void setPasswordQuestion(String passwordQuestion) {
		this.passwordQuestion = passwordQuestion;
	}

	public String getPasswordAnswer() {
		return passwordAnswer;
	}

	public void setPasswordAnswer(String passwordAnswer) {
		this.passwordAnswer = passwordAnswer;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getTelephone() {
		return telephone;
	}

	public void setTelephone(String telephone) {
		this.telephone = telephone;
	}

	public String getMobilePhone() {
		return mobilePhone;
	}

	public void setMobilePhone(String mobilePhone) {
		this.mobilePhone = mobilePhone;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Double getBalance() {
		return balance;
	}

	public void setBalance(Double balance) {
		this.balance = balance;
	}

	public String getAccessCode() {
		return accessCode;
	}

	public void setAccessCode(String accessCode) {
		this.accessCode = accessCode;
	}

	public Boolean getIsActivated() {
		return isActivated;
	}

	public void setIsActivated(Boolean isActivated) {
		this.isActivated = isActivated;
	}

	public String getActivateCode() {
		return activateCode;
	}

	public void setActivateCode(String activateCode) {
		this.activateCode = activateCode;
	}

	public java.util.Date getCreatedDate() {
		return createdDate;
	}

	public void setCreatedDate(java.util.Date createdDate) {
		this.createdDate = createdDate;
	}

	public List<Role> getRoles() {
		return roles;
	}

	public void setRoles(List<Role> roles) {
		this.roles = roles;
	}

	public Location getDropOffLocation() {
		return dropOffLocation;
	}

	public void setDropOffLocation(Location dropOffLocation) {
		this.dropOffLocation = dropOffLocation;
	}

	public List<Message> getMessages() {
		return messages;
	}

	public void setMessages(List<Message> messages) {
		this.messages = messages;
	}

	public List<Order> getOrders() {
		return orders;
	}

	public void setOrders(List<Order> orders) {
		this.orders = orders;
	}

	public List<AccountRecord> getAccountRecords() {
		return accountRecords;
	}

	public void setAccountRecords(List<AccountRecord> accountRecords) {
		this.accountRecords = accountRecords;
	}
	
	public List<UserActivityRecord> getUserActivityRecords() {
		return userActivityRecords;
	}

	public void setUserActivityRecords(List<UserActivityRecord> userActivityRecords) {
		this.userActivityRecords = userActivityRecords;
	}

	public Boolean getIsEmailOrderStatus() {
		return isEmailOrderStatus;
	}

	public void setIsEmailOrderStatus(Boolean isEmailOrderStatus) {
		if (this.isEmailOrderStatus == Boolean.FALSE
				&& isEmailOrderStatus == Boolean.TRUE) {
			this.isEmailStatusCancel = Boolean.TRUE;
			this.isEmailStatusPrepare = Boolean.TRUE;
			this.isEmailStatusConfirm = Boolean.TRUE;
			this.isEmailStatusDeliver = Boolean.TRUE;
			this.isEmailStatusPay = Boolean.TRUE;
		}
		if (this.isEmailOrderStatus == Boolean.TRUE
				&& isEmailOrderStatus == Boolean.FALSE) {
			this.isEmailStatusCancel = Boolean.FALSE;
			this.isEmailStatusPrepare = Boolean.FALSE;
			this.isEmailStatusConfirm = Boolean.FALSE;
			this.isEmailStatusDeliver = Boolean.FALSE;
			this.isEmailStatusPay = Boolean.FALSE;
		}
		this.isEmailOrderStatus = isEmailOrderStatus;

	}

	public Boolean getIsEmailStatusConfirm() {
		return isEmailStatusConfirm;
	}

	public void setIsEmailStatusConfirm(Boolean isEmailStatusConfirm) {
		this.isEmailStatusConfirm = isEmailStatusConfirm;
	}

	public Boolean getIsEmailStatusPrepare() {
		return isEmailStatusPrepare;
	}

	public void setIsEmailStatusPrepare(Boolean isEmailStatusPrepare) {
		this.isEmailStatusPrepare = isEmailStatusPrepare;
	}

	public Boolean getIsEmailStatusDeliver() {
		return isEmailStatusDeliver;
	}

	public void setIsEmailStatusDeliver(Boolean isEmailStatusDeliver) {
		this.isEmailStatusDeliver = isEmailStatusDeliver;
	}

	public Boolean getIsEmailStatusPay() {
		return isEmailStatusPay;
	}

	public void setIsEmailStatusPay(Boolean isEmailStatusPay) {
		this.isEmailStatusPay = isEmailStatusPay;
	}

	public Boolean getIsEmailStatusCancel() {
		return isEmailStatusCancel;
	}

	public void setIsEmailStatusCancel(Boolean isEmailStatusCancel) {
		this.isEmailStatusCancel = isEmailStatusCancel;
	}

	public boolean getIsPrepaid() {
		return isPrepaid;
	}

	public void setIsPrepaid(boolean isPrepaid) {
		this.isPrepaid = isPrepaid;
	}

//	public Boolean getIsDisabled() {
//		return isEnabled;
//	}
//
//	public void setIsDisabled(Boolean isDisabled) {
//		this.isEnabled = isDisabled;
//	}

	public LANGUAGE getLanguage() {
		return language;
	}

	public void setLanguage(LANGUAGE language) {
		this.language = language;
	}

	public TITLE getTitle() {
		return title;
	}

	public void setTitle(TITLE title) {
		this.title = title;
	}

	public String getMemo() {
		return memo;
	}

	public void setMemo(String memo) {
		this.memo = memo;
	}

	public Boolean getIsEnabled() {
		return isEnabled;
	}

	public void setIsEnabled(Boolean isEnabled) {
		this.isEnabled = isEnabled;
	}

	public Boolean getIsExpired() {
		return isExpired;
	}

	public void setIsExpired(Boolean isExpired) {
		this.isExpired = isExpired;
	}

	public Boolean getIsLocked() {
		return isLocked;
	}

	public void setIsLocked(Boolean isLocked) {
		this.isLocked = isLocked;
	}

	public void setPrepaid(boolean isPrepaid) {
		this.isPrepaid = isPrepaid;
	}

	public String getUsername() {
		return this.email;
	}

	public boolean isAccountNonExpired() {
		return !this.getIsExpired();
	}

	public boolean isAccountNonLocked() {
		return !this.getIsLocked();
	}

	public boolean isCredentialsNonExpired() {
		return true;
	}

	public boolean isEnabled() {
		return this.getIsActivated() && this.getIsEnabled();
	}

}
